package com.rongkang.interview.juc.volatiletest;

/**
 * @Description:
 * @author: 荣康
 * @date: 2021/12/1
 */
public class SingletonDemo {
    private static volatile SingletonDemo instance = null;

    //私有构造方法
    private SingletonDemo() {
        System.out.println(Thread.currentThread().getName() + "\t  我是单例模式构造方法");
    }

    public static /*synchronized*/ SingletonDemo getInstance() {
        if (instance == null) {
            //同步代码段的时候，进行检测   DCL机制  双端检锁机制不一定是线程安全的，原因是因为有
            synchronized (SingletonDemo.class) {
                if (instance == null) {
                    instance = new SingletonDemo();
                }
            }
        }
        return instance;
    }

    public static void main(String[] args) {
        //在单线程的情况下没有线程安全问题，构造方法只打印一次
//        System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
//        System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
//        System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
//        System.out.println(SingletonDemo.getInstance() == SingletonDemo.getInstance());
        //在多线程情况下会出现线程安全问题
        /**
         * 解决方法一： 在getInstance上添加synchronized，但是他是属于重量级的同步机制，他只允许一个线程去访问获取实例的方法
         * 但是保证了数据的一致性，而降低了并发性，因此采用的比较少
         *
         * 解决方发二：使用DCL机制，双端检索机制，并且在这个变量上加上volatile，防止他指令重排
         */
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                SingletonDemo.getInstance();
            }, String.valueOf(i)).start();
        }
    }
}
